package de.koller.aframe.util.misc;

import de.koller.aframe.plain.PlainRasterFloat;
import de.koller.oceanFramework.util.MIn;
import de.koller.oceanFramework.util.MOut;
import java.io.File;
import java.util.LinkedList;
import java.util.Random;

public class BufferedRandomFloat {

	public static final int MAX_LOADED_CHUNKS = 64;
	public static final int CHUNK_SIZE = 512;
	
	private final Random rnd;
	private final String bufferRoot;
	
	private LinkedList<FloatChunk> chunks = new LinkedList<>();
	
	public BufferedRandomFloat( String bufferRoot, Random rnd ) {
		this.rnd = rnd;
		this.bufferRoot = bufferRoot;
	}
	
	public float get( int ax, int ay, int level, int type ) {
		int vx = (int)Math.floor( (float)ax / (float)CHUNK_SIZE ) * CHUNK_SIZE;
		int vy = (int)Math.floor( (float)ay / (float)CHUNK_SIZE ) * CHUNK_SIZE;
		int dx = ax - vx;
		int dy = ay - vy;
		
		FloatChunk c = null;
		for( FloatChunk f : chunks ) {
			if( f.type != type ) continue;
			if( f.level != level ) continue;
			if( f.vx != vx ) continue;
			if( f.vy != vy ) continue;
			
			c = f;
			break;
		}
		
		if( c != null )
			chunks.remove( c );
		else
			c = new FloatChunk( vx, vy, level, type );
		
		chunks.addFirst( c );
		
		while( chunks.size() > MAX_LOADED_CHUNKS )
			chunks.removeLast();
		
		return c.raster.getValue( dx, dy );
	}
	
	private class FloatChunk {
		private final int vx, vy, level, type;
		private PlainRasterFloat raster = new PlainRasterFloat( CHUNK_SIZE, CHUNK_SIZE );
		
		public FloatChunk( int vx, int vy, int level, int type ) {
			this.vx = vx;
			this.vy = vy;
			this.level = level;
			this.type = type;
	
			load();
		}

		private String getFileName() {
			return bufferRoot + "/rf_" + vx + "_" + vy + "_" + level + "_" + type + ".chunk";
		}
		
		private void load() {
			File f = new File( getFileName() );
			f.deleteOnExit();
			
			if( f.exists() ) {
				MIn in = new MIn( getFileName() );
				System.arraycopy( in.readFloat( CHUNK_SIZE*CHUNK_SIZE ), 0, raster.data, 0, CHUNK_SIZE*CHUNK_SIZE );
				in.close();
			} else {
				for( int i = 0; i < raster.data.length; i++ )
					raster.data[i] = rnd.nextFloat();
				MOut out = new MOut( getFileName(), true );
				out.writeFloat( raster.data );
				out.close();
			}
		}
		
		@Override
		public int hashCode() {
			int hash = 5;
			hash = 53 * hash + this.vx;
			hash = 53 * hash + this.vy;
			hash = 53 * hash + this.level;
			hash = 53 * hash + this.type;
			return hash;
		}

		@Override
		public boolean equals( Object obj ) {
			if( obj == null ) {
				return false;
			}
			if( getClass() != obj.getClass() ) {
				return false;
			}
			final FloatChunk other = ( FloatChunk ) obj;
			if( this.vx != other.vx ) {
				return false;
			}
			if( this.vy != other.vy ) {
				return false;
			}
			if( this.level != other.level ) {
				return false;
			}
			if( this.type != other.type ) {
				return false;
			}
			return true;
		}

	}

	public static void main( String[] args ) {
		BufferedRandomFloat f = new BufferedRandomFloat( "./screenshots/testdata", new Random() );
		
		System.out.println( f.get( 102783, 328973, 3, 4 ) );
		System.out.println( f.get( 3, 328973, 2, 4 ) );
		
		System.out.println( f.get( 102783, 328973, 3, 4 ) );
	}
	
}
